package digitRecognitionProblem;

import genetic_algorithm.Chromosome;
import genetic_algorithm.FitnessFunction;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import mlp.Mlp;
import utils.VectorClassificationPair;

public class DigitRecognitionMlpFitness implements FitnessFunction {

	
	static List<VectorClassificationPair > testData;
	File testSet;
	Mlp classifier; 
	List<Mlp> classifiers = null; 
		
	static public void initTestData(String testSetFileName)
	{
		Scanner scan = null;
		try {
			scan = new Scanner(new File(testSetFileName));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

		testData = new ArrayList<VectorClassificationPair>();
		String line;
		int cls;
		while(scan.hasNext())
		{
			line = scan.nextLine();
			cls = Integer.parseInt(line.substring(0,1));
			String[] inputsStr = line.substring(2).split(",");
			float[] inputs = new float[inputsStr.length];
			for(int i =0 ; i < inputsStr.length ; i++){inputs[i] = Float.parseFloat(inputsStr[i]);}
			testData.add(new VectorClassificationPair(inputs, cls));
		}
		scan.close();
	}
	
	static public void initTestData(String testSetFileName, int classify)
	{
		Scanner scan = null;
		try {
			scan = new Scanner(new File(testSetFileName));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

		testData = new ArrayList<VectorClassificationPair>();
		String line;
		int cls;
		while(scan.hasNext())
		{
			line = scan.nextLine();
			cls = Integer.parseInt(line.substring(0,1));
			
			cls = (cls == classify) ? Mlp.POSITIVE : Mlp.NEGATIVE;
			
			String[] inputsStr = line.substring(2).split(",");
			float[] inputs = new float[inputsStr.length];
			for(int i =0 ; i < inputsStr.length ; i++){inputs[i] = Float.parseFloat(inputsStr[i]);}
			testData.add(new VectorClassificationPair(inputs, cls));
		}
		scan.close();
	}
	
	public DigitRecognitionMlpFitness(Mlp mlp)
	{
		classifier = mlp;
	}
	
	public DigitRecognitionMlpFitness(List<Mlp> mlpsList)
	{
		classifiers = mlpsList;
	}
	
	public DigitRecognitionMlpFitness()
	{
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public double getFitness(Chromosome chromosome) {

		
		if(chromosome != null)
		{
			ArrayList<ArrayList< float[]> > weights = new ArrayList<ArrayList<float[]> >();
			for(Object o : chromosome.getAllValues()){weights.add((ArrayList< float[]>) o);}
			classifier =  Mlp.createByWeights(weights);			
		}
		
		double success = 0;
//		int counter = 0;
		for(VectorClassificationPair data : testData)
		{
			int learnResult = classifiers == null ? classifier.getClassification(data.getVector()) : getClassifiersClassify(data.getVector(), false);
			int expected = data.getClassification();
			if(expected == learnResult)
			{
				success++;
			}
			else
			{
//				System.out.println("****{error: ("+testData.indexOf(data)+") learnResult: "+learnResult+", expected: "+expected+"}****");
//				System.out.println("****{error: ("+counter+") learnResult: "+learnResult+", expected: "+expected+"}****");
//				if(classifiers != null)
//				{
//					System.out.println("--------   ERROR ("+testData.indexOf(data)+")   ----------");
//					getClassifiersClassify(data.getVector(), true);
//					System.out.println("Expected: " +expected+ ",  Result: "+ learnResult);
//					System.out.println("-----------------------------");
//				}
				
			}
//			++counter;
		}
//		System.out.println("");
//		System.out.println("test set: "+testData.size()+" success: "+success);
		return (success/testData.size())*100.0;
		
	}
	
	
	
	private int getClassifiersClassify(float[] vector, boolean print)
	{
		float[] outputs = new float[classifiers.size()];
		for (int i = 0 ; i < classifiers.size() ; ++i)
		{
			outputs[i] = classifiers.get(i).evaluate(vector)[0];
		}
		int bestIndex = 0;
		float bestOut = -2;
		for(int i = 0 ; i < classifiers.size() ; ++i)
		{
			if(print)System.out.print(i +": " +outputs[i]+" ");
			if(outputs[i] > bestOut)
			{
				bestOut = outputs[i];
				bestIndex = i;
			}
		}
		if(print)System.out.print("\n");
		return bestIndex;	
	}
}
